package com.zhl.framework.core.client;

import com.alibaba.fastjson.JSON;
import com.zhl.framework.core.common.RpcDecoder;
import com.zhl.framework.core.common.RpcEncoder;
import com.zhl.framework.core.common.RpcInvocation;
import com.zhl.framework.core.common.RpcProtocol;
import com.zhl.framework.core.common.config.ClientConfig;
import com.zhl.framework.core.common.jdk.JDKProxyFactory;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import lombok.Data;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import static com.zhl.framework.core.common.cache.CommonClientCache.SEND_QUEUE;

/**
 * @Author: ZhangLu In DLUT
 * @since: 1.0.0
 * @Description:
 */
@Data
public class Client {
    /**
     * TODO 这里需要查询一下日志的用法
     */
    private Logger logger = LoggerFactory.getLogger(Client.class);

    private static EventLoopGroup clientGroup = new NioEventLoopGroup();

    private ClientConfig clientConfig;



    public static void main(String[] args) {
        // 创建客户端
        Client client = new Client();
        // 创建配置选项
        ClientConfig clientConfig = new ClientConfig();
        clientConfig.setPort(9090);
        clientConfig.setServerAddr("localhost");
        client.setClientConfig(clientConfig);
        // 启动客户端
        client.startClientApplication();


    }

    private RpcReference startClientApplication() {
        clientGroup = new NioEventLoopGroup();
        Bootstrap bootstrap = new Bootstrap();
        bootstrap.group(clientGroup)
                .channel(NioSocketChannel.class) // 设置客户端连接的通道为 NioSocketChannel，支持TCP协议
                .handler(new ChannelInitializer<SocketChannel>() {
                    /**
                     *  客户端与服务端建立完连接之后，就会调用这个初始化方法
                     * @param ch 建立的通道
                     * @throws Exception
                     */
                    @Override
                    protected void initChannel(SocketChannel ch) throws Exception {
                        ch.pipeline().addLast(new RpcDecoder());
                        ch.pipeline().addLast(new RpcEncoder());
                        ch.pipeline().addLast(new ClientHandler());
                    }
                });
        // 客户端与服务端进行连接
        ChannelFuture channelFuture = bootstrap.connect(clientConfig.getServerAddr(), clientConfig.getPort());
        logger.info("========== 服务启动 ===========");
        this.startClient(channelFuture);
        RpcReference rpcReference = new RpcReference(new JDKProxyFactory());
        return rpcReference;
    }

    /**
     * 开启发送线程，异步
     * @param channelFuture 获取的连接通道对象
     */
    private void startClient(ChannelFuture channelFuture) {
        Thread asyncSendJob = new Thread(new AsyncSendJob(channelFuture));
        asyncSendJob.start();
    }

    private class AsyncSendJob implements Runnable {
        private ChannelFuture channelFuture;

        public AsyncSendJob(ChannelFuture channelFuture) {
            this.channelFuture = channelFuture;
        }

        @Override
        public void run() {
            while (true){
                // 阻塞模式
                try {
                    // 从调用队列中获取一个 RPC 调用
                    RpcInvocation rpcInvocation = SEND_QUEUE.take();
                    // 将调用对象 RpcInvocation 序列化成 JSON字符串
                    String json = JSON.toJSONString(rpcInvocation);
                    // 将 JSON 字符串转化成协议对象 RpcProtocol
                    RpcProtocol rpcProtocol = new RpcProtocol(json.getBytes());
                    channelFuture.channel().writeAndFlush(rpcProtocol);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
        }
    }
}
